package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.ArticleConfigMapper;
import com.heima.article.mapper.ArticleContentMapper;
import com.heima.article.mapper.ArticleMapper;
import com.heima.article.service.IArticleService;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.dtos.ArticleHomeDto;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.article.pojos.ApArticleContent;
import com.heima.model.article.vos.HotArticleVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.es.vos.SearchArticleVo;
import com.heima.model.wemedia.pojos.WmNews;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper,ApArticle> implements IArticleService {

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private ArticleConfigMapper configMapper;

    @Autowired
    private ArticleContentMapper contentMapper;

    @Autowired
    private Configuration configuration;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;
    /**
     * 文章列表查询
     *
     * @param dto
     * @param type
     * @return
     */
    @Override
    public ResponseResult loadArticleList(ArticleHomeDto dto, Long type) {
        //1.参数校验
        if(dto.getSize()!=null){
            dto.setSize(10);
        }
        if(!type.equals(2)&&!type.equals(1)){
            type = 2L;
        }
        //文章频道校验
        if(StringUtils.isEmpty(dto.getTag())){
            dto.setTag("__all__");
        }

        //时间校验
        if(dto.getMaxBehotTime() == null) dto.setMaxBehotTime(new Date());
        if(dto.getMinBehotTime() == null) dto.setMinBehotTime(new Date());
        //2.调用mapper接口
        List<ApArticle> apArticles = articleMapper.loadArticleList(dto, type);

        //3.返回数据
        return ResponseResult.okResult(apArticles);
    }



    /**
     * 新增三剑客
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveArticle3(ArticleDto dto) {
        ApArticle apArticle=new ApArticle();
        //1.判断是否是新增
        if(dto.getId()==null){
            //如果是则保存三剑客
            //保存article

            BeanUtils.copyProperties(dto,apArticle);
            save(apArticle);
            //保存article_config
            ApArticleConfig aprticleConfig=new ApArticleConfig(apArticle.getId());
            configMapper.insert(aprticleConfig);

            //保存article_content
            ApArticleContent aparticleContent=new ApArticleContent();
            aparticleContent.setArticleId(apArticle.getId());
            aparticleContent.setContent(dto.getContent());
            contentMapper.insert(aparticleContent);

        }else{
            //如果不是，则修改文章及修改文章内容
            apArticle = getById(dto.getId());
            if(apArticle!=null){
                BeanUtils.copyProperties(dto,apArticle);
                updateById(apArticle);
            }


            //先查文章内容，在修改
            ApArticleContent apArticleContent = contentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery()
                    .eq(ApArticleContent::getArticleId, apArticle.getId()));
            if(apArticleContent!=null){
                apArticleContent.setContent(dto.getContent());
                contentMapper.updateById(apArticleContent);
            }
        }

        //异步调用生成静态文件的操作
        try {
            buildArticleInfoToMinio(apArticle.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }

        //异步通知通过kafka到Es中
        sendMessageToEs(dto);



        return ResponseResult.okResult(apArticle.getId()!=null?apArticle.getId():"");
    }

    /**
     * 异步通知通过kafka到Es中
     */
    private void sendMessageToEs(ArticleDto dto) {
        SearchArticleVo searchArticleVo=new SearchArticleVo();
        BeanUtils.copyProperties(dto,searchArticleVo);
        kafkaTemplate.send("sync_es_topic", JSON.toJSONString(searchArticleVo));
    }


    /**
     * 生成静态文件并上传到minio中
     */
    @Async
    public void buildArticleInfoToMinio(Long articleId) throws Exception {
        //1.获取模板
        Template template = configuration.getTemplate("article.ftl");

        //2.获取数据模型,查询文件内容表
        ApArticleContent apArticleContent = contentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, articleId));

        Map dataModel=new HashMap<>();
        dataModel.put("content", JSONArray.parseArray(apArticleContent.getContent()));


        //3.生成静态文件，合成
        StringWriter out=new StringWriter();
        template.process(dataModel,out);

        //4.把静态文件存入到minio中
        ByteArrayInputStream inputStream=new ByteArrayInputStream(out.toString().getBytes(StandardCharsets.UTF_8));
        String path = fileStorageService.uploadHtmlFile("",
                UUID.randomUUID().toString() + ".html",
                inputStream);


        //5.把保存地址保存到ap_article表中static_url字段中
        ApArticle aparticle=articleMapper.selectById(apArticleContent.getArticleId());
        if(aparticle!=null){
            aparticle.setStaticUrl(path);
            articleMapper.updateById(aparticle);
        }
    }

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 文章列表查询plus.查询的就是首页
     *
     * @param dto ,推荐频道  __all__  如果其他频道则是id
     * @param
     * @return
     */
    @Override
    public ResponseResult loadArticleList2(ArticleHomeDto dto) {
        String hotArticleVoListStr =null;
        //1.查询redis
        if(dto.getTag().equals("__all__")){
            hotArticleVoListStr= redisTemplate.opsForValue().get("hot_article_first_page" + dto.getTag());
        }else{//其他频道
            hotArticleVoListStr= redisTemplate.opsForValue().get("hot_article_first_page_" + dto.getTag());
        }

        //2.封装数据
        List<HotArticleVo> articleVoList = JSONArray.parseArray(hotArticleVoListStr, HotArticleVo.class);

        return ResponseResult.okResult(articleVoList);
    }
}
